package com.blacktea.magicapi.policy.magicapiuiuser;

import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.blacktea.magicapi.base.BaseConstant;
import com.blacktea.magicapi.base.core.RedisCache;
import com.blacktea.magicapi.entites.domain.MguMagicUiUser;
import com.blacktea.magicapi.entites.dto.UiUserDto;
import org.springframework.data.redis.core.ListOperations;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: black tea
 * @date: 2022/2/15 15:32
 */
public class UiUserRedisPolicy implements UiUserPolicy{

    private final static String TOKEN_PREFIX = "ui_user_token"+ BaseConstant.Symbol.DOUBLE_COLON;
    private final static String USER_PREFIX = "ui_user"+BaseConstant.Symbol.DOUBLE_COLON;
    private final static String IP_WHITELIST = "ip_whitelist"+BaseConstant.Symbol.DOUBLE_COLON;
    private final static String IP_BLACKLIST = "ip_blacklist"+BaseConstant.Symbol.DOUBLE_COLON;

    private final RedisCache redisCache = SpringUtil.getBean("redisCache");

    @Override
    public UiUserDto getUser(String token) {
        return redisCache.getCacheObject(this.combinationToken(token));
    }

    @Override
    public synchronized String buildToken(UiUserDto uiUser) {
        // 登录成功,随机生成一个token
        String token = IdUtil.simpleUUID();
        redisCache.setCacheObject(this.combinationToken(token),uiUser,2,TimeUnit.HOURS);
        redisCache.setCacheObject
            (
                this.combinationUser(token,uiUser.getUser().getUsername())
                ,uiUser
                ,2
                ,TimeUnit.HOURS
            );
        return token;
    }

    @Override
    public List<UiUserDto> users() {
        Collection<String> keys = redisCache.keys(this.combinationToken(BaseConstant.Symbol.ASTERISK));
        return redisCache.getMultiValue(keys);
    }

    @Override
    public synchronized void removeByToken(String token) {
        UiUserDto uiUserDto = this.getUser(token);
        Optional.ofNullable(uiUserDto).ifPresent(user ->{
            redisCache.deleteObject(this.combinationToken(token));
            redisCache.deleteObject(this.combinationUser(token,user.getUser().getUsername()));
        });
    }

    @Override
    public List<UiUserDto> getByUsername(String username) {
        Collection<String> keys = redisCache.keys(this.combinationUser(BaseConstant.Symbol.ASTERISK,username));
        return redisCache.getMultiValue(keys);
    }

    @Override
    public String getWhitelist(MguMagicUiUser user) {
        return this.getIps(user,IP_WHITELIST);
    }

    @Override
    public void putWhitelist(MguMagicUiUser user, List<String> ips) {
        this.putIp(user,ips,IP_WHITELIST);
    }

    @Override
    public void removeByIpWhitelist(MguMagicUiUser user, List<String> matchIps) {
      this.removeIps(user,matchIps,IP_WHITELIST);
    }

    @Override
    public void removeAllWhitelist(MguMagicUiUser user) {
        this.removeAll(user,IP_WHITELIST);
    }

    @Override
    public void replaceWhitelist(MguMagicUiUser user, Map<String, String> replaceIpMap) {
       this.replaceIps(user,replaceIpMap,IP_WHITELIST);
    }

    @Override
    public String getBlacklist(MguMagicUiUser user) {
        return this.getIps(user,IP_BLACKLIST);
    }

    @Override
    public void putBlacklist(MguMagicUiUser user, List<String> ips) {
        this.putIp(user,ips,IP_BLACKLIST);
    }

    @Override
    public void removeByIpBlacklist(MguMagicUiUser user, List<String> matchIps) {
        this.removeIps(user,matchIps,IP_BLACKLIST);
    }

    @Override
    public void removeAllBlacklist(MguMagicUiUser user) {
        this.removeAll(user,IP_BLACKLIST);
    }

    @Override
    public void replaceBlacklist(MguMagicUiUser user, Map<String, String> replaceIpMap) {
        this.replaceIps(user,replaceIpMap,IP_BLACKLIST);
    }

    private String combinationToken(String token){
        return TOKEN_PREFIX+token;
    }

    private String combinationUser(String token,String username){
        return USER_PREFIX+token+BaseConstant.Symbol.DOUBLE_COLON+username;
    }

    private String combinationIPKey(String ipPrefix,String userId){
        return ipPrefix+userId;
    }

    private String getIps(MguMagicUiUser user, String ipType){
        StringJoiner joiner = new StringJoiner(",");
        List<String> ipWhitelist = redisCache.getCacheList(this.combinationIPKey(ipType,user.getId()));
        ipWhitelist.forEach(joiner::add);
        return joiner.toString();
    }

    private void putIp(MguMagicUiUser user, List<String> ips, String ipType){
        redisCache.getRedisTemplate()
                .opsForList()
                .rightPushAll(this.combinationIPKey(ipType,user.getId()),ips);
    }

    private void removeIps(MguMagicUiUser user, List<String> matchIps, String ipType){
        matchIps.forEach(ip -> {
            redisCache.getRedisTemplate()
                    .opsForList()
                    .remove(this.combinationIPKey(ipType,user.getId()),1,ip);
        });
    }

    private void removeAll(MguMagicUiUser user, String ipType){
        redisCache.getRedisTemplate()
                .opsForList()
                .trim(this.combinationIPKey(ipType,user.getId()),0,-1);
    }

    private void replaceIps(MguMagicUiUser user, Map<String, String> replaceIpMap, String ipType){
        replaceIpMap.forEach((k,v)->{
            ListOperations listOperations = redisCache.getRedisTemplate().opsForList();
            String id = user.getId();
            Long index = listOperations.lastIndexOf(this.combinationIPKey(ipType,id),k);
            listOperations.set(this.combinationIPKey(ipType, id),index,v);
        });
    }
}
